package controllers

import (
    "gouniapp/configs"
	"context"
	"fmt"
	"encoding/json"
	"image"
	"image/color"
	"image/draw"
	"image/jpeg"
	"log"
	"net/url"
	"os"
	"path/filepath"
	"strconv"
	"net/http"
    "strings"
	"github.com/gin-gonic/gin"
	"sync"
	"math"
	"github.com/golang/freetype" 
	"github.com/golang/freetype/truetype" 
	"golang.org/x/sync/errgroup" 
	"github.com/nfnt/resize"
    "github.com/fogleman/gg"
    "golang.org/x/image/font"
)

type (
	CertificateInput struct {
		ID         int      `json:"id"`
		Overwrite  bool     `json:"overwrite"`      // 是否覆盖 
		NameField  string   `json:"name_field"`     // 哪列作为文件名k1 
		StorageKey string   `json:"storage_key"`    // 证书存储在哪列k3 
		IDs        []uint   `json:"ids"`            //行id 
	}

	FieldConfig struct {
		Name       string       `json:"name"`        //字段
		X          float64      `json:"x"`           //横坐标
		Y          float64      `json:"y"`           //纵坐标
		Width      float64      `json:"width"`       //图片宽
		Height     float64      `json:"height"`      //图片高
		FontSize   float64      `json:"fontsize"`    //文字大小
		FontColor  string       `json:"fontcolor"`   //文字颜色
		FontFamily string       `json:"fontfamily"`  //字体
		TextWidth  float64      `json:"textwidth"`  //文本行宽 
		RowHeight  float64      `json:"rowheight"`   // 行间距
	}

	FontCache struct {
		cache map[string]*truetype.Font 
		mu    sync.RWMutex 
	}
)

// 全局字体缓存（线程安全版本）
var fontCache = &FontCache{
	cache: make(map[string]*truetype.Font),
}

// 主入口函数
func Sczs(c *gin.Context) {
	var query CertificateInput 
	if err := c.ShouldBindJSON(&query); err != nil {
		JsonResponse(c, http.StatusBadRequest, "Invalid request parameters", nil)
		return 
	}
	fmt.Println(query.IDs)
	// 执行生成证书任务 
	code, msg := GenerateCertificates(context.Background(), query)
	if code != 0 {
		JsonResponse(c, http.StatusInternalServerError, msg, nil)
		return 
	}
	JsonResponse(c, http.StatusOK, "生成任务进行中", nil)
}

func GenerateCertificates(ctx context.Context, input CertificateInput) (int, string) {
	// 验证输入 
	if err := validateInput2(input); err != nil {
		return 1, err.Error()
	}
	// 加载项目配置 
	bgConfig, templateConfig, err := loadProjectConfig(input.ID)
	if err != nil {
		return 1, fmt.Sprintf("配置加载失败: %v", err)
	}
	// 加载背景图片 
	bgImage, err := loadBackgroundImage(templateConfig.BackgroundURL)
	if err != nil {
		return 1, fmt.Sprintf("背景图片加载失败: %v", err)
	}
	// 处理数据 
	if err := processData2(input, bgConfig, templateConfig, bgImage); err != nil {
		return 1, fmt.Sprintf("数据处理失败: %v", err)
	}
	return 0, "操作成功"
}

// 验证输入 
func validateInput2(input CertificateInput) error {
	switch {
    case input.ID == 0:
		return fmt.Errorf("查询项目不存在")
    case input.NameField == "":
		return fmt.Errorf("文件名字段不能为空")
	case input.StorageKey == "":
		return fmt.Errorf("存储字段不能为空")
	default:
		return nil 
	}
}

// 加载项目配置和证书模板 
func loadProjectConfig(projectID int) (configs.FormSchema, configs.PicTemplate, error) {
	var formSchema configs.FormSchema
	if projectID == 0 {
        return formSchema, configs.PicTemplate{}, fmt.Errorf("查询项目id为0")
    }
	if err := configs.DB.First(&formSchema, projectID).Error; err != nil {
		return formSchema, configs.PicTemplate{}, fmt.Errorf("查询项目不存在: %v", err)
	}
	var template configs.PicTemplate
	if formSchema.Zsmb == 0 {
	    return formSchema, configs.PicTemplate{}, fmt.Errorf("查询项目模板id为0")
	}
	if err := configs.DB.First(&template, formSchema.Zsmb).Error; err != nil {
		return formSchema, template, fmt.Errorf("查询项目模板配置不存在: %v", err)
	}
	return formSchema, template, nil 
}

// 加载背景图片 
func loadBackgroundImage(imageURL string) (image.Image, error) {
	parsedURL, err := url.Parse(imageURL)
	if err != nil {
		return nil, fmt.Errorf("图片URL解析失败: %v", err)
	}
	// 从URL中提取路径部分，忽略域名部分
	filePath := filepath.Join(parsedURL.Path)
	// 在实际路径中去掉URL路径中的前导斜杠（如果存在）
	filePath = filepath.Clean(filePath)
	// 去掉路径中的前导斜杠
	filePath = strings.TrimPrefix(filePath, "/")
	// 检查文件是否存在
	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		return nil, fmt.Errorf("背景图不存在: %v", filePath)
	}
	file, err := os.Open(filePath)
	if err != nil {
		return nil, fmt.Errorf("背景图打开失败: %v", err)
	}
	defer file.Close()
	img, _, err := image.Decode(file)
	if err != nil {
		return nil, fmt.Errorf("背景图解码失败: %v", err)
	}
	return img, nil
}

// 处理数据 
func processData2(input CertificateInput, bgConfig configs.FormSchema, template configs.PicTemplate, bgImage image.Image) error {
	query := configs.DB.Table(bgConfig.TableName)
	if !input.Overwrite {
		query.Where(fmt.Sprintf("%s IS NULL OR %s = ''", input.StorageKey, input.StorageKey)) //覆盖原数据
	}
	if len(input.IDs) > 0 {
		query.Where("id IN ?", input.IDs)   //指定行
	}
	var results []map[string]interface{}
	if err := query.Scan(&results).Error; err != nil {
		return fmt.Errorf("数据库查询失败: %v", err)
	}
	var fieldConfigs []FieldConfig 
	if err := json.Unmarshal([]byte(template.Fields), &fieldConfigs); err != nil {
        return fmt.Errorf("字段配置解析失败: %v", err)
    }
	for _, result := range results {
		if err := processzs(input, bgConfig, template, bgImage, fieldConfigs, result); err != nil {
			log.Printf("处理记录失败: %v", err)
			continue 
		}
	}
	return nil 
}

// 处理单条记录 
func processzs(input CertificateInput, bgConfig configs.FormSchema, template configs.PicTemplate, bgImage image.Image, fieldConfigs []FieldConfig, record map[string]interface{}) error {
	cleanProjectName := strings.ReplaceAll(bgConfig.FormName, " ", "")
	fileName := fmt.Sprintf("%v", record[input.NameField])
	outputPath := filepath.Join("uploads", "zs", cleanProjectName, fileName+".jpg")
	if err := os.MkdirAll(filepath.Dir(outputPath), 0755); err != nil {
		return fmt.Errorf("目录创建失败: %v", err)
	}
	if err := generateCertificate(bgImage, fieldConfigs, record, outputPath); err != nil {
		return fmt.Errorf("证书生成失败: %v", err)
	}
	return updateDatabaseRecord(bgConfig.TableName, input.StorageKey, outputPath, record)
}

// 生成证书 
func generateCertificate(bgImage image.Image, configs []FieldConfig, data map[string]interface{}, outputPath string) error {
	canvas := image.NewRGBA(bgImage.Bounds())
	draw.Draw(canvas, canvas.Bounds(), bgImage, image.Point{}, draw.Src)
	for _, cfg := range configs {
		// 如果字段是图片类型
		if isImageField(data, cfg.Name) {
			imageField := fmt.Sprintf("%v", data[cfg.Name])
			imageToOverlay, err := loadImage(imageField)
			if err != nil {
				log.Printf("图片加载失败: %v", err)
				continue
			}
			err = overlayImage(canvas, imageToOverlay, cfg.X, cfg.Y, cfg.Width, cfg.Height)
			if err != nil {
				log.Printf("图片叠加失败: %v", err)
				continue
			}
		} else {
			// 处理文本字段
			if err := drawTextField(canvas, cfg, data); err != nil {
				log.Printf("文本绘制失败: %v", err)
				continue
			}
		}
	}
	return saveImageFile(canvas, outputPath)
}

// 是否图片字段
func isImageField(data map[string]interface{}, fieldName string) bool {
	value := fmt.Sprintf("%v", data[fieldName])
	return strings.HasSuffix(value, ".jpg") || strings.HasSuffix(value, ".png")
}

// 加载图片字段数据
func loadImage(imageURL string) (image.Image, error) {
	parsedURL, err := url.Parse(imageURL)
	if err != nil {
		return nil, fmt.Errorf("图片URL解析失败: %v", err)
	}
	// 如果URL没有域名部分，则可能是相对路径
	var filePath string
	if parsedURL.IsAbs() {
		// 如果URL是绝对路径
		filePath = filepath.Join(os.Getenv("ASSETS_ROOT"), parsedURL.Path)
	} else {
		// 如果URL是相对路径
		filePath = filepath.Join(os.Getenv("ASSETS_ROOT"), parsedURL.Path)
	}
	// 清理路径，去除多余的斜杠和路径规范化
	filePath = filepath.Clean(filePath)
	// 去掉前导斜杠，确保路径格式正确
	filePath = strings.TrimPrefix(filePath, "/")
	// 检查文件是否存在
	if _, err := os.Stat(filePath); os.IsNotExist(err) {
		return nil, fmt.Errorf("图片文件不存在: %v", filePath)
	}
	// 打开文件
	file, err := os.Open(filePath)
	if err != nil {
		return nil, fmt.Errorf("图片文件打开失败: %v", err)
	}
	defer file.Close()
	// 解码图片
	img, _, err := image.Decode(file)
	if err != nil {
		return nil, fmt.Errorf("图片解码失败: %v", err)
	}
	return img, nil
}

// 将图片叠加到背景上
func overlayImage(dst *image.RGBA, src image.Image, x, y, newWidth, newHeight float64) error {
    // 调整源图片大小（添加四舍五入）
	resizedSrc := resize.Resize(
		uint(math.Round(newWidth)), 
		uint(math.Round(newHeight)), 
		src, 
		resize.Lanczos3,
	)
	// 计算叠加位置（添加四舍五入）
	rect := resizedSrc.Bounds().Add(image.Point{
		X: int(math.Round(x)),
		Y: int(math.Round(y)),
	})
	draw.Draw(dst, rect, resizedSrc, image.Point{}, draw.Over)
	return nil
}

// 绘制文本字段 
func drawTextField(canvas *image.RGBA, cfg FieldConfig, data map[string]interface{}) error {
    text := fmt.Sprintf("%v", data[cfg.Name])
    font, err := fontCache.GetFont(cfg.FontFamily)
    if err != nil {
        return fmt.Errorf("字体加载失败: %v", err)
    }
    colorValue, err := parseColor(cfg.FontColor)
    if err != nil {
        return fmt.Errorf("颜色解析失败: %v", err)
    }
    if cfg.TextWidth > 0 {
        ctx := gg.NewContextForRGBA(canvas)
        face := truetype.NewFace(font, &truetype.Options{
            Size:    cfg.FontSize,
            DPI:     72,
        })
        // 修正行高逻辑
        rowHeight := cfg.RowHeight
        if rowHeight <= 0 {
            rowHeight = 5.0 // 默认行高
        }
        // 优化基线计算（加字体高度的3/4）
        baseY := cfg.Y + cfg.FontSize*0.75
        TextAlign(
            ctx,
            text,
            cfg.TextWidth,
            math.Round(cfg.X),
            math.Round(baseY), // 修正后的Y坐标
            cfg.FontSize,
            face,
            colorValue,
            rowHeight,
        )
    } else {
        // 原始单行绘制方式
        ctx := freetype.NewContext()
        ctx.SetFont(font)
        ctx.SetFontSize(cfg.FontSize)
        ctx.SetClip(canvas.Bounds())
        ctx.SetDst(canvas)
        ctx.SetSrc(image.NewUniform(colorValue))
        xPos := int(math.Round(cfg.X))
        yOffset := int(ctx.PointToFixed(cfg.FontSize)) >> 6
        yPos := int(math.Round(cfg.Y)) + yOffset
        pt := freetype.Pt(xPos, yPos)
        if _, err := ctx.DrawString(text, pt); err != nil {
            return fmt.Errorf("文本绘制失败: %v", err)
        }
    }
    return nil
}

// 设置了TextWidth时文字自动换行
func TextAlign(ctx *gg.Context, str string, width, x, y, fontSize float64, fontFace font.Face, color color.Color, rowHeight float64) {
    runes := []rune(str)
    tempStr := ""
    ctx.SetFontFace(fontFace)
    ctx.SetColor(color)
    for i := 0; i < len(runes); {
        char := runes[i]
        tempStr += string(char)
        // 预判下一个字符
        var probeStr string
        if i+1 < len(runes) {
            probeStr = tempStr + string(runes[i+1])
        } else {
            probeStr = tempStr
        }
        // 精确测量
        probeWidth, _ := ctx.MeasureString(probeStr)
        // 换行条件判断
        if probeWidth > (width - 10) {
            // 绘制当前行
            ctx.DrawString(tempStr, x, y)
            y += fontSize + rowHeight
            tempStr = ""
            i++ // 处理下一个字符
        } else if i == len(runes)-1 { // 最后字符处理
            ctx.DrawString(tempStr, x, y)
            i++
        } else {
            i++ // 继续累积字符
        }
    }
}

// 保存图片文件 
func saveImageFile(img image.Image, path string) error {
	file, err := os.Create(path)
	if err != nil {
		return fmt.Errorf("文件创建失败: %v", err)
	}
	defer file.Close()
	if err := jpeg.Encode(file, img, &jpeg.Options{Quality: 90}); err != nil {
		return fmt.Errorf("图片编码失败: %v", err)
	}
	return nil 
}

// 更新数据库记录 
func updateDatabaseRecord(tableName, storageKey, filePath string, record map[string]interface{}) error {
	updateData := map[string]interface{}{
		storageKey: configs.MyURL + filePath,
	}
	result := configs.DB.Table(tableName).Where("id = ?", record["id"]).Updates(updateData)
	if result.Error != nil {
		return fmt.Errorf("数据库更新失败: %v", result.Error)
	}
	if result.RowsAffected == 0 {
		return fmt.Errorf("未找到匹配记录")
	}
	return nil 
}

// 获取字体 
func (fc *FontCache) GetFont(fontFamily string) (*truetype.Font, error) {
	fc.mu.RLock()  
	if font, exists := fc.cache[fontFamily]; exists {
		fc.mu.RUnlock()  
		return font, nil 
	}
	fc.mu.RUnlock()  
	fc.mu.Lock()  
	defer fc.mu.Unlock()  
	if font, exists := fc.cache[fontFamily]; exists {
		return font, nil 
	}
	fontPath := resolveFontPath(fontFamily)
	fontData, err := os.ReadFile(fontPath)
	if err != nil {
		return nil, fmt.Errorf("字体文件读取失败: %v", err)
	}
	font, err := truetype.Parse(fontData)
	if err != nil {
		return nil, fmt.Errorf("字体解析失败: %v", err)
	}
	fc.cache[fontFamily]   = font 
	return font, nil 
}

// 加载字体路径 
func resolveFontPath(fontFamily string) string {
    fmt.Println("加载字体:", fontFamily)
	fontMap := configs.Config.GetStringMapString("fonts")    //获取字体映射如："宋体": "simsun.ttc"
	fontFileName := fontMap[fontFamily]
	if fontFileName == "" {
		fontFileName = "uploads/fonts/simsun.ttc"
	}
	return filepath.Join(fontFileName)
}

// 解析颜色 
func parseColor(colorStr string) (color.RGBA, error) {
    fmt.Println("解析颜色:", colorStr)
	if strings.HasPrefix(colorStr, "#") {
		return parseHexColor(colorStr)
	}
	if strings.HasPrefix(colorStr, "rgba(") {
		return parseRGBA(colorStr)
	}
	return color.RGBA{}, fmt.Errorf("不支持的颜色格式: %s", colorStr)
}

// 解析十六进制颜色 
func parseHexColor(hexStr string) (color.RGBA, error) {
    hexStr = strings.TrimPrefix(hexStr, "#")
    if len(hexStr) != 6 && len(hexStr) != 8 {
        return color.RGBA{}, fmt.Errorf("无效的十六进制颜色格式")
    }
    var r, g, b, a uint8 
    var err error 
    // 处理Red通道 
    rByte, err := strconv.ParseUint(hexStr[0:2], 16, 8)
    if err != nil {
        return color.RGBA{}, fmt.Errorf("无法解析Red通道: %v", err)
    }
    r = uint8(rByte)
    // 处理Green通道 
    gByte, err := strconv.ParseUint(hexStr[2:4], 16, 8)
    if err != nil {
        return color.RGBA{}, fmt.Errorf("无法解析Green通道: %v", err)
    }
    g = uint8(gByte)
    // 处理Blue通道 
    bByte, err := strconv.ParseUint(hexStr[4:6], 16, 8)
    if err != nil {
        return color.RGBA{}, fmt.Errorf("无法解析Blue通道: %v", err)
    }
    b = uint8(bByte)
    // 如果有Alpha通道，则处理 
    if len(hexStr) == 8 {
        aByte, err := strconv.ParseUint(hexStr[6:8], 16, 8)
        if err != nil {
            return color.RGBA{}, fmt.Errorf("无法解析Alpha通道: %v", err)
        }
        a = uint8(aByte)
    } else {
        a = 0xff // 默认全透明 
    }
    return color.RGBA{
        R: r,
        G: g,
        B: b,
        A: a,
    }, nil 
}

// 解析RGBA颜色字符串 
func parseRGBA(rgbaStr string) (color.RGBA, error) {
	fields := strings.FieldsFunc(rgbaStr[5:len(rgbaStr)-1], func(r rune) bool {
		return r == ','
	})
	if len(fields) < 3 || len(fields) > 4 {
		return color.RGBA{}, fmt.Errorf("无效的RGBA颜色格式")
	}
	rVal := strings.Trim(fields[0], "()")
	gVal := strings.Trim(fields[1], "()")
	bVal := strings.Trim(fields[2], "()")
	aVal := "255"
	if len(fields) >= 4 {
		aVal = strings.Trim(fields[3], "()")
	}
	r, errR := strconv.Atoi(rVal)
	g, errG := strconv.Atoi(gVal)
	b, errB := strconv.Atoi(bVal)
	a, errA := strconv.Atoi(aVal)
	if errR != nil || errG != nil || errB != nil || errA != nil {
		return color.RGBA{}, fmt.Errorf("颜色值转换错误")
	}
	if r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255 || a < 0 || a > 255 {
		return color.RGBA{}, fmt.Errorf("颜色值超出范围")
	}
	return color.RGBA{
		R: uint8(r),
		G: uint8(g),
		B: uint8(b),
		A: uint8(a),
	}, nil 
}

// Worker池实现（优化版）
type WorkerPool struct {
	workChan chan func() error 
	errGroup *errgroup.Group 
}

func NewWorkerPool(workers int) *WorkerPool {
	g, _ := errgroup.WithContext(context.Background())
	pool := &WorkerPool{
		workChan: make(chan func() error),
		errGroup: g,
	}
	for i := 0; i < workers; i++ {
		pool.errGroup.Go(func()   error { return pool.worker()   })
	}
	return pool 
}

func (p *WorkerPool) worker() error {
	for task := range p.workChan   {
		if err := task(); err != nil {
			log.Printf("任务执行失败: %v", err)
			p.errGroup.Wait()  
			return err 
		}
	}
	return nil 
}

func (p *WorkerPool) Submit(task func() error) {
	p.workChan   <- task 
}

func (p *WorkerPool) Stop() error {
	close(p.workChan)  
	return p.errGroup.Wait()  
}